vlwkaos' digital garden

JavaScript - Event Delegation

๐Ÿ‘€ [[JavaScript - Event Bubbling VS Event Capturing]]

๋งŽ์€ Element์—์„œ ๋น„์Šทํ•˜๊ฒŒ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ ํ•˜๋‚˜์˜ handler๋ฅผ ์ด์šฉํ•˜์—ฌ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•

event.target๋กœ ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์ง„์›์ง€๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด <table>์ด ์žˆ๊ณ  ํ…Œ์ด๋ธ” ์…€์„ ํด๋ฆญํ•˜๋ฉด ์ƒ‰์น ํ•ด์ฃผ๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋‹ฌ๊ณ  ์‹ถ๋‹ค๊ณ  ํ•  ๋•Œ, ๊ฐ๊ฐ ๋‹ฌ์ž๋‹ˆ ๊ต‰์žฅํžˆ ๋ฒˆ๊ฑฐ๋กญ๋‹ค. ์•„๋ž˜์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

let selectedTd

// ํ…Œ์ด๋ธ” ์ „์ฒด์— listener๋ฅผ ๋ถ€์ฐฉํ•œ๋‹ค.
table.onclick = function (event) {
  let target = event.target // ํด๋ฆญ์ด ๋ฐœ์ƒํ•œ๊ณณ์ด

  if (target.tagName != "TD") return // ํ…Œ์ด๋ธ” ์…€์ด ์•„๋‹ˆ๋ฉด ์ค‘์ง€

  highlight(target) // ๋งž์œผ๋ฉด ์ „๋‹ฌ
}

function highlight(td) {
  if (selectedTd) {
    // ์ด๋ฏธ ์ƒ‰์น ๋œ ๊ฒƒ์ด ์žˆ์œผ๋ฉด ์ œ๊ฑฐ
    selectedTd.classList.remove("highlight")
  }
  selectedTd = td
  selectedTd.classList.add("highlight") // target์ด ์…€์ด๊ธฐ๋•Œ๋ฌธ์— ๊ฑฐ๊ธฐ์— ๋ถ€์ฐฉ
}

ํ•˜์ง€๋งŒ ํ•ญ์ƒ ์ž˜ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๋งŒ์•ฝ <td>๋‚ด๋ถ€์— ๋‹ค๋ฅธ element๊ฐ€ ์žˆ์œผ๋ฉด event.target์ด ๋‹ค๋ฅด๊ฒŒ ๋‚˜์˜ฌ ๊ฒƒ์ด๋‹ค.

์ด๋Ÿด ๋–„๋Š” event.target.closest('td') ์ด๋Ÿฐ์‹์œผ๋กœ selector์™€ ์ผ์น˜ํ•˜๋Š” ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋ถ€๋ชจ element๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  <table>์ด ๊ฐ–๊ณ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ฉด ๋œ๋‹ค.

markup์˜ data-set์ด์šฉํ•˜๊ธฐ

<div id="menu">
  <button data-action="save">Save</button>
  <button data-action="load">Load</button>
  <button data-action="search">Search</button>
</div>

<script>
  class Menu {
    constructor(elem) {
      this._elem = elem;
      elem.onclick = this.onClick.bind(this); // (*)
    }

    save() {
      alert('saving');
    }

    load() {
      alert('loading');
    }

    search() {
      alert('searching');
    }

    onClick(event) {
      let action = event.target.dataset.action;
      if (action) {
        this[action]();
      }
    };
  }

  new Menu(menu);
</script>
JavaScript - Event Delegation